use anyhow::Result;
use bytes::Bytes;
use pyo3::{prelude::*, types::PyString};
use pyo3::types::PyBytes;
use serde::{Deserialize, Serialize};

pub mod tick;
pub mod user;
pub mod order;
pub mod bar;
pub mod currency;

/// Python 模块
#[pymodule]
fn eztrade_client(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_class::<PyMessage>()?;
    m.add_class::<tick::PriceLevel>()?;
    m.add_class::<tick::TickData>()?;
    m.add_class::<user::Authority>()?;
    m.add_class::<user::Position>()?;
    m.add_class::<user::Portfolio>()?;
    m.add_class::<order::Order>()?;
    m.add_class::<order::Direction>()?;
    m.add_class::<order::PositionEffect>()?;
    m.add_class::<order::OrderStatus>()?;
    m.add_class::<order::Operation>()?;
    m.add_class::<order::OrderOperation>()?;
    m.add_class::<bar::BarData>()?;
    m.add_class::<currency::Currency>()?;
    Ok(())
}

pub trait DataTransferObject: Serialize + for<'de> Deserialize<'de> + Sized {
    /// 将 TickData 序列化为 JSON 字节数组
    fn to_json_bytes(&self) -> Result<Bytes> {
        let json_string = serde_json::to_string(self)?;
        Ok(Bytes::from(json_string))
    }

    /// 从 JSON 字节数组反序列化 TickData
    fn from_json_bytes(bytes: &Bytes) -> Result<Self> {
        let json_str = std::str::from_utf8(bytes)?;
        let tick_data = serde_json::from_str(json_str)?;
        Ok(tick_data)
    }

    /// 将 TickData 序列化为二进制字节数组 (使用 bincode)
    fn to_binary_bytes(&self) -> Result<Bytes> {
        let binary_data = bincode::serialize(self)?;
        Ok(Bytes::from(binary_data))
    }

    /// 从二进制字节数组反序列化 TickData (使用 bincode)
    fn from_binary_bytes(bytes: &Bytes) -> Result<Self> {
        let tick_data = bincode::deserialize(bytes)?;
        Ok(tick_data)
    }
}

/// 消息枚举，包含不同类型的消息, 用于 server 和 client 之间的通信
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum Message {
    Authority(user::Authority),       // 用户鉴权传递
    Notification(String),             // 通知消息
    Order(order::Order),              // 订单消息（包括下单反馈、订单查询等）
    TickData(tick::TickData),         // Tick数据
    BarData(bar::BarData),            // Bar数据(占位符还未实现)
    OrderOperation(order::OrderOperation), // 指令消息(查询/撤单)
    QueryAccount(),                   // 账户信息查询
    Portfolio(user::Portfolio),       // 账户信息
    SubscribeTick { symbol: String }, // 订阅Tick(Symbol)
}

impl Message {
    /// 将 Message 序列化为二进制字节数组 (使用 bincode)
    pub fn to_binary_bytes(&self) -> Result<Bytes> {
        let mut binary_data = bincode::serialize(self)?;
        let checksum = binary_data.iter().fold(0u8, |acc, &x| acc.wrapping_add(x));
        binary_data.push(checksum);
        Ok(Bytes::from(binary_data))
    }

    /// 从二进制字节数组反序列化 Message (使用 bincode)
    pub fn from_binary_bytes(bytes: &Bytes) -> Result<Self> {
        let deserialized: Self = bincode::deserialize(&bytes[..bytes.len()-1])?;
        let checksum = bytes.last().copied().unwrap_or(0);
        let calculated_checksum = bytes[..bytes.len()-1].iter().fold(0u8, |acc, &x| acc.wrapping_add(x));
        if checksum != calculated_checksum {
            return Err(anyhow::anyhow!("Checksum mismatch"));
        }
        Ok(deserialized)
    }

    /// 将 Message 序列化为 JSON 字节数组
    pub fn to_json_bytes(&self) -> Result<Bytes> {
        let json_string = serde_json::to_string(self)?;
        Ok(Bytes::from(json_string))
    }

    /// 从 JSON 字节数组反序列化 Message
    pub fn from_json_bytes(bytes: &Bytes) -> Result<Self> {
        let json_str = std::str::from_utf8(bytes)?;
        let message = serde_json::from_str(json_str)?;
        Ok(message)
    }
}

// 新的 PyMessage 结构体，用于 Pyo3 接口 (Python 不支持直接使用 Message 枚举)
#[pyclass(unsendable)] // unsendable 因为 PyObjectRef 不支持 Send
#[derive(Debug, Clone)] // Clone 是为了 get_data 返回克隆
pub struct PyMessage {
    pub inner: Message,
}

#[pymethods]
impl PyMessage {
    #[new]
    pub fn new(_py: Python, obj: &Bound<'_, PyAny>) -> PyResult<Self> {
        if let Ok(tick_data) = obj.extract::<tick::TickData>() {
            Ok(PyMessage {
                inner: Message::TickData(tick_data),
            })
        } else if let Ok(order) = obj.extract::<order::Order>() {
            Ok(PyMessage {
                inner: Message::Order(order),
            })
        } else if let Ok(authority) = obj.extract::<user::Authority>() {
            Ok(PyMessage {
                inner: Message::Authority(authority),
            })
        } else if let Ok(portfolio) = obj.extract::<user::Portfolio>() {
            Ok(PyMessage {
                inner: Message::Portfolio(portfolio),
            })
        } else if let Ok(order_operation) = obj.extract::<order::OrderOperation>() {
            Ok(PyMessage {
                inner: Message::OrderOperation(order_operation),
            })
        } else if let Ok(bar_data) = obj.extract::<bar::BarData>() {
            Ok(PyMessage {
                inner: Message::BarData(bar_data),
            })
        } else if let Ok(notification) = obj.extract::<String>() {
            Ok(PyMessage {
                inner: Message::Notification(notification),
            })
        } else {
            Err(pyo3::exceptions::PyTypeError::new_err(
                "Object must be an instance of TickData, Order, Authority, Portfolio, OrderOperation, BarData, or String",
            ))
        }
    }

    /// 创建一个QueryAccount消息
    #[staticmethod]
    #[pyo3(name = "query_account")]
    pub fn py_query_account(_py: Python) -> Self {
        PyMessage {
            inner: Message::QueryAccount(),
        }
    }

    /// 创建一个 SubscribeTick(symbol) 消息
    #[staticmethod]
    #[pyo3(name = "subscribe_tick")]
    pub fn py_subscribe_tick(_py: Python, symbol: &Bound<'_, PyString>) -> Self {
        PyMessage {
            inner: Message::SubscribeTick {
                symbol: symbol.to_string_lossy().into_owned(),
            },
        }
    }

    /// 将 PyMessage 序列化为二进制字节数组 (使用 bincode)
    #[pyo3(name = "to_binary_bytes")]
    pub fn py_to_binary_bytes(&self, py: Python) -> PyResult<PyObject> {
        match self.inner.to_binary_bytes() {
            Ok(bytes) => Ok(PyBytes::new_bound(py, &bytes).into()),
            Err(e) => Err(pyo3::exceptions::PyValueError::new_err(format!(
                "Serialization error: {}",
                e
            ))),
        }
    }

    /// 从二进制字节数组反序列化 PyMessage (使用 bincode)
    #[staticmethod]
    #[pyo3(name = "from_binary_bytes")]
    pub fn py_from_binary_bytes(_py: Python, bytes: &Bound<'_, PyBytes>) -> PyResult<Self> {
        let byte_slice = Bytes::copy_from_slice(bytes.as_bytes());
        match Message::from_binary_bytes(&byte_slice) {
            Ok(message) => Ok(PyMessage { inner: message }),
            Err(e) => Err(pyo3::exceptions::PyValueError::new_err(format!(
                "Deserialization error: {}",
                e
            ))),
        }
    }

    /// 获取 PyMessage 中包含的数据类型
    #[pyo3(name = "get_data_type")]
    pub fn get_data_type(&self) -> String {
        match self.inner {
            Message::TickData(_) => "TickData".to_string(),
            Message::Order(_) => "Order".to_string(),
            Message::Notification(_) => "String".to_string(),
            Message::Authority(_) => "Authority".to_string(),
            Message::Portfolio(_) => "Portfolio".to_string(),
            Message::OrderOperation(_) => "OrderOperation".to_string(),
            Message::BarData(_) => "BarData".to_string(),
            Message::QueryAccount() => "QueryAccount".to_string(),
            Message::SubscribeTick { .. } => "SubscribeTick".to_string(),
        }
    }

    /// 获取 PyMessage 中包含的数据对象
    #[pyo3(name = "get_data")]
    pub fn get_data(&self, py: Python) -> PyObject {
        match &self.inner {
            // 注意这里使用 &self.inner
            Message::TickData(tick_data) => tick_data.clone().into_py(py),
            Message::Order(order) => order.clone().into_py(py),
            Message::Notification(notification) => {
                // 将 Notification 转换为 Python 字符串
                PyString::new_bound(py, &notification).into()
            }
            Message::Authority(authority) => authority.clone().into_py(py),
            Message::Portfolio(portfolio) => portfolio.clone().into_py(py),
            Message::OrderOperation(order_operation) => order_operation.clone().into_py(py),
            Message::BarData(bar_data) => bar_data.clone().into_py(py),
            Message::QueryAccount() => {
                // QueryAccount 没有数据，返回 None
                py.None()
            }
            Message::SubscribeTick { symbol } => PyString::new_bound(py, symbol).into(),
        }
    }

    fn __repr__(&self) -> String {
        format!("Message({:?})", self.get_data_type())
    }
}
